home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / ue312src.zip / NECDOS.C < prev    next >
C/C++ Source or Header  |  1993-03-03  |  28KB  |  1,113 lines

  1. /*    NECDOS.C:    Operating specific I/O and Spawning functions
  2.             under the MSDOS operating system
  3.             on the NEC PC-9801 series computer
  4.             for MicroEMACS 3.12
  5.             (C)Copyright 1993 by Daniel M. Lawrence
  6. */
  7.  
  8. #include        <stdio.h>
  9. #include    "estruct.h"
  10. #include    "eproto.h"
  11.  
  12. #ifdef    MSDOS
  13. #include        "edef.h"
  14. #include    "elang.h"
  15.  
  16. /* The Mouse driver only works with typeahead defined */
  17. #if    MOUSE
  18. #undef    TYPEAH
  19. #define    TYPEAH    1
  20. #endif
  21.  
  22. #if  TURBO
  23. #include <conio.h>
  24. #include <dir.h>
  25. #include <dos.h>
  26. #include <bios.h>
  27.  
  28. struct ffblk fileblock;    /* structure for directory searches */
  29. #endif
  30. #if    MSC | IC
  31. #include <dos.h>
  32.  
  33. struct find_t fileblock;    /* structure for directory searches */
  34. #endif
  35.  
  36. #if     LATTICE | MSC | DTL | TURBO | IC | AZTEC | MWC
  37. union REGS rg;        /* cpu register for use of DOS calls */
  38. struct SREGS segreg;    /* cpu segment registers         */
  39. int nxtchar = -1;    /* character held from type ahead    */
  40. #endif
  41.  
  42. #if    MSC | TURBO | IC
  43. #include    <process.h>
  44. #endif
  45.  
  46. /*    Some global variable    */
  47. #define INBUFSIZ    40
  48. static int mexist;    /* is the mouse driver installed? */
  49. static int nbuttons;    /* number of buttons on the mouse */
  50. static int oldright;    /* old right button status */
  51. static int oldleft;    /* old left button status */
  52.  
  53. PASCAL NEAR execprog(char *cmd);
  54.  
  55. /*    input buffers and pointers    */
  56.  
  57. #define    IBUFSIZE    64    /* this must be a power of 2 */
  58.  
  59. unsigned char in_buf[IBUFSIZE];    /* input character buffer */
  60. int in_next = 0;        /* pos to retrieve next input character */
  61. int in_last = 0;        /* pos to place most recent input character */
  62.  
  63. in_init()    /* initialize the input buffer */
  64.  
  65. {
  66.     in_next = in_last = 0;
  67. }
  68.  
  69. in_check()    /* is the input buffer non-empty? */
  70.  
  71. {
  72.     if (in_next == in_last)
  73.         return(FALSE);
  74.     else
  75.         return(TRUE);
  76. }
  77.  
  78. in_put(event)
  79.  
  80. int event;    /* event to enter into the input buffer */
  81.  
  82. {
  83.     in_buf[in_last++] = event;
  84.     in_last &= (IBUFSIZE - 1);
  85. }
  86.  
  87. int in_get()    /* get an event from the input buffer */
  88.  
  89. {
  90.     register int event;    /* event to return */
  91.  
  92.     event = in_buf[in_next++];
  93.     in_next &= (IBUFSIZE - 1);
  94.     return(event);
  95. }
  96.  
  97. /*
  98.  * This function is called once to set up the terminal device streams.
  99.  */
  100.  
  101. PASCAL NEAR ttopen()
  102.  
  103. {
  104. #if    MOUSE
  105.     long miaddr;    /* mouse interupt routine address */
  106. #endif
  107.  
  108.     strcpy(os, "MSDOS");
  109. #if     (HP150 == 0) & LATTICE
  110.     /* kill the ctrl-break interupt */
  111.     rg.h.ah = 0x33;        /* control-break check dos call */
  112.     rg.h.al = 1;        /* set the current state */
  113.     rg.h.dl = 0;        /* set it OFF */
  114.     intdos(&rg, &rg);    /* go for it! */
  115. #endif
  116.     /* on all screens we are not sure of the initial position
  117.        of the cursor                    */
  118.     ttrow = 999;
  119.     ttcol = 999;
  120.  
  121. #if    MOUSE
  122.     /* check if the mouse drive exists first */
  123.     rg.x.ax = 0x3533;    /* look at the interrupt 33 address */
  124.  
  125. #if    MSC | TURBO | IC | DTL | LATTICE | MWC
  126.     int86x(0x21, &rg, &rg, &segreg);
  127.     miaddr = (((long)segreg.es) << 16) + (long)rg.x.bx;
  128.     if (miaddr == 0 || *(char * far)miaddr == 0xcf) {
  129. #endif
  130. #if    AZTEC
  131.     sysint(0x21, &rg, &rg);
  132.     miaddr = (((long)rg.x.es) << 16) + (long)rg.x.bx;
  133.     if (miaddr == 0 || *(char *)miaddr == 0xcf) {
  134. #endif
  135.         mexist = FALSE;
  136.         return;
  137.     }
  138.  
  139.     /* and then check for the mouse itself */
  140.     rg.x.ax = 0;        /* mouse status flag */
  141.     int86(0x33, &rg, &rg);    /* check for the mouse interupt */
  142.     mexist = (rg.x.ax != 0);
  143.  
  144.     /* override this missing value from the NEC */
  145.     nbuttons = 2;
  146.  
  147.     /* initialize our character input queue */
  148.     in_init();
  149.     if (mexist == FALSE)
  150.         return;
  151.  
  152.     /* if the mouse exists.. get it in the upper right corner */
  153.     rg.x.ax = 4;        /* set mouse cursor position */
  154.     rg.x.cx = (term.t_ncol - 1) << 3;    /* last col of display */
  155.     rg.x.dx = 0;        /* top row */
  156.     int86(0x33, &rg, &rg);
  157.  
  158.     /* set the display plane for the mouse */
  159.     rg.x.ax = 18;        /* set screen for displaying cursor */
  160.     rg.x.bx = 0;        /* in GRAY */
  161.     int86(0x33, &rg, &rg);
  162.  
  163. #if    0
  164.     /* and set its attributes */
  165.     rg.x.ax = 10;        /* set text cursor */
  166.     rg.x.bx = 0;        /* software text cursor please */
  167.     rg.x.cx = 0x77ff;    /* screen mask */
  168.     rg.x.dx = 0x7700;    /* cursor mask */
  169.     int86(0x33, &rg, &rg);
  170. #endif
  171. #else    /* !MOUSE */
  172.     mexist = 0;
  173. #endif    /* !MOUSE */
  174. }
  175.  
  176. maxlines(lines)        /* set number of vertical rows for mouse */
  177.  
  178. int lines;    /* # of vertical lines */
  179.  
  180. {
  181. #if    MOUSE
  182.     if (mexist) {
  183. #endif
  184.     }
  185. /* #endif*/
  186. }
  187.  
  188. /*
  189.  * This function gets called just before we go back home to the command
  190.  * interpreter. On VMS it puts the terminal back in a reasonable state.
  191.  * Another no-operation on CPM.
  192.  */
  193. PASCAL NEAR ttclose()
  194. {
  195. #if     (HP150 == 0) & LATTICE
  196.     /* restore the ctrl-break interrupt */
  197.     rg.h.ah = 0x33;        /* control-break check dos call */
  198.     rg.h.al = 1;        /* set the current state */
  199.     rg.h.dl = 1;        /* set it ON */
  200.     intdos(&rg, &rg);    /* go for it! */
  201. #endif
  202. }
  203.  
  204. /*
  205.  * Write a character to the display. On VMS, terminal output is buffered, and
  206.  * we just put the characters in the big array, after checking for overflow.
  207.  * On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on
  208.  * MS-DOS (use the very very raw console output routine).
  209.  */
  210.  
  211. PASCAL NEAR ttputc(c)
  212.  
  213. int c;
  214.  
  215. {
  216. #if     MWC
  217.         putcnb(c);
  218. #endif
  219.  
  220. #if    (LATTICE | AZTEC | TURBO | IC | MSC) & ~IBMPC
  221.     bdos(6, c, 0);
  222. #endif
  223. }
  224.  
  225. /*
  226.  * Flush terminal buffer. Does real work where the terminal output is buffered
  227.  * up. A no-operation on systems where byte at a time terminal I/O is done.
  228.  */
  229. PASCAL NEAR ttflush()
  230. {
  231. }
  232.  
  233. int doschar()    /* call the dos to get a char */
  234.  
  235. {
  236.  
  237.     register unsigned int c;    /* extended character to return */ 
  238.  
  239.     rg.h.ah = 7;        /* dos Direct Console Input call */
  240.     intdos(&rg, &rg);
  241.     if (rg.h.al == 0x1d) {    /* function key!! */
  242.         rg.h.ah = 7;    /* get the next character */
  243.         intdos(&rg, &rg);
  244.         c = extcode(rg.h.al);
  245.         in_put(c >> 8);        /* prefix byte */
  246.         in_put(c & 255);    /* event code byte */
  247.         return(0);        /* extended escape sequence */
  248.     }
  249.     return(rg.h.al & 255);
  250. }
  251.  
  252. /*
  253.  * Read a character from the terminal, performing no editing and doing no echo
  254.  * at all. Also mouse events are forced into the input stream here.
  255.  */
  256. PASCAL NEAR ttgetc()
  257.  
  258. {
  259.     register int c;        /* character read */
  260.  
  261. ttc:    /* return any keystrokes waiting in the
  262.        type ahead buffer */
  263.     if (in_check())
  264.         return(in_get());
  265.  
  266. #if    TYPEAH
  267.     if (typahead())
  268.         return(doschar());
  269.  
  270.     /* with no mouse, this is a simple get char routine */
  271.     if (mexist == FALSE || mouseflag == FALSE)
  272.         return(doschar());
  273.  
  274. #if    MOUSE
  275.     /* turn the mouse cursor on */
  276.     rg.x.ax = 1;    /* Show Cursor */
  277.     int86(0x33, &rg, &rg);
  278.  
  279.     /* loop waiting for something to happen */
  280.     while (TRUE) {
  281.         if (typahead())
  282.             break;
  283.         if (checkmouse())
  284.             break;
  285.     }
  286.  
  287.     /* turn the mouse cursor back off */
  288.     rg.x.ax = 2;    /* Hide Cursor */
  289.     int86(0x33, &rg, &rg);
  290.  
  291.     goto ttc;
  292. #endif    /* MOUSE */
  293. #else    /* TYPEAH */
  294.     return(doschar());
  295. #endif    /* TYPEAH */
  296. }
  297.  
  298. #if    MOUSE
  299. checkmouse()
  300.  
  301. {
  302.     register int k;        /* current bit/button of mouse */
  303.     register int event;    /* encoded mouse event */
  304.     int mousecol;        /* current mouse column */
  305.     int mouserow;        /* current mouse row */
  306.     int sstate;        /* current shift key status */
  307.     int leftbutton;        /* status of the left mouse button */
  308.     int rightbutton;    /* status of the right mouse button */
  309.  
  310.     /* check to see if any mouse buttons are different */
  311.     rg.x.ax = 3;    /* Get button status and mouse position */
  312.     int86(0x33, &rg, &rg);
  313.     leftbutton = rg.x.ax;
  314.     rightbutton = rg.x.bx;
  315.  
  316.     mousecol = rg.x.cx >> 3;
  317.     mouserow = rg.x.dx >> 4;
  318.  
  319.     if ((rightbutton == oldright) &&
  320.         (leftbutton == oldleft))
  321.              return(FALSE);
  322.  
  323.     /* get the shift key status as well */
  324.     rg.h.ah = 2;    /* return current shift status */
  325.     int86(0x18, &rg, &rg);
  326.     sstate = rg.h.al;
  327.  
  328.     if (rightbutton != oldright) {
  329.         /* the right button changed, generate an event */
  330.         in_put(0);
  331.         in_put(MOUS >> 8);
  332.         in_put(mousecol);
  333.         in_put(mouserow);
  334.  
  335.         event = ((rightbutton != 0) ? 0 : 1);    /* up or down? */
  336.         event += 4;            /* right button */
  337.         if (sstate & 1)            /* shifted */
  338.             event += 'A';
  339.         else if (sstate & 16)        /* controled? */
  340.             event += 1;
  341.         else
  342.             event += 'a';        /* plain */
  343.         in_put(event);
  344.         oldright = rightbutton;
  345.         return(TRUE);
  346.     }
  347.  
  348.     if (leftbutton != oldleft) {
  349.         /* the left button changed, generate an event */
  350.         in_put(0);
  351.         in_put(MOUS >> 8);
  352.         in_put(mousecol);
  353.         in_put(mouserow);
  354.  
  355.         event = ((leftbutton != 0) ? 0 : 1);    /* up or down? */
  356.         if (sstate & 1)            /* shifted */
  357.             event += 'A';
  358.         else if (sstate & 16)        /* controled? */
  359.             event += 1;
  360.         else
  361.             event += 'a';        /* plain */
  362.         in_put(event);
  363.         oldleft = leftbutton;
  364.         return(TRUE);
  365.     }
  366.     return(FALSE);
  367. }
  368. #endif
  369.  
  370. #if    TYPEAH
  371. /* typahead:    Check to see if any characters are already in the
  372.         keyboard buffer
  373. */
  374.  
  375. PASCAL NEAR typahead()
  376.  
  377. {
  378.     int flags;    /* cpu flags from dos call */
  379.  
  380.     rg.x.ax = 0x4406;    /* IOCTL input status */
  381.     rg.x.bx = 0;        /* File handle = stdin */
  382. #if    MSC | DTL
  383.     int86(0x21,&rg,&rg);
  384.     flags = rg.h.al;
  385. #else
  386. #if    LATTICE | AZTEC | TURBO | IC
  387.     flags = intdos(&rg, &rg);
  388. #else
  389.     intcall(&rg, &rg, 0x21);
  390.     flags = rg.x.flags;
  391. #endif
  392. #endif
  393.     if (flags & 1)        /* AL = 0xFF if ready */
  394.         return(TRUE);
  395.     else
  396.         return(FALSE);
  397. }
  398. #endif
  399.  
  400. /*
  401.  * Create a subjob with a copy of the command intrepreter in it. When the
  402.  * command interpreter exits, mark the screen as garbage so that you do a full
  403.  * repaint. Bound to "^X C".
  404.  */
  405.  
  406. PASCAL NEAR spawncli(f, n)
  407.  
  408. int f, n;
  409.  
  410. {
  411.     /* don't allow this command if restricted */
  412.     if (restflag)
  413.         return(resterr());
  414.  
  415.         movecursor(term.t_nrow, 0);             /* Seek to last line.   */
  416.         TTflush();
  417.     TTkclose();
  418.     shellprog("");
  419.     TTkopen();
  420.         sgarbf = TRUE;
  421.         return(TRUE);
  422. }
  423.  
  424. /*
  425.  * Run a one-liner in a subjob. When the command returns, wait for a single
  426.  * character to be typed, then mark the screen as garbage so a full repaint is
  427.  * done. Bound to "C-X !".
  428.  */
  429. PASCAL NEAR spawn(f, n)
  430.  
  431. int f, n;
  432.  
  433. {
  434.         register int s;
  435.         char line[NLINE];
  436.  
  437.     /* don't allow this command if restricted */
  438.     if (restflag)
  439.         return(resterr());
  440.  
  441.         if ((s=mlreply("!", line, NLINE)) != TRUE)
  442.                 return(s);
  443.     movecursor(term.t_nrow - 1, 0);
  444.     TTkclose();
  445.         shellprog(line);
  446.     TTkopen();
  447.     /* if we are interactive, pause here */
  448.     if (clexec == FALSE) {
  449.             mlputs(TEXT6);
  450. /*                     "\r\n\n[End]" */
  451.             tgetc();
  452.         }
  453.         sgarbf = TRUE;
  454.         return (TRUE);
  455. }
  456.  
  457. /*
  458.  * Run an external program with arguments. When it returns, wait for a single
  459.  * character to be typed, then mark the screen as garbage so a full repaint is
  460.  * done. Bound to "C-X $".
  461.  */
  462.  
  463. PASCAL NEAR execprg(f, n)
  464.  
  465. {
  466.         register int s;
  467.         char line[NLINE];
  468.  
  469.     /* don't allow this command if restricted */
  470.     if (restflag)
  471.         return(resterr());
  472.  
  473.         if ((s=mlreply("$", line, NLINE)) != TRUE)
  474.                 return(s);
  475.     movecursor(term.t_nrow - 1, 0);
  476.     TTkclose();
  477.         execprog(line);
  478.     TTkopen();
  479.     /* if we are interactive, pause here */
  480.     if (clexec == FALSE) {
  481.             mlputs(TEXT6);
  482. /*                     "\r\n\n[End]" */
  483.             tgetc();
  484.         }
  485.         sgarbf = TRUE;
  486.         return (TRUE);
  487. }
  488.  
  489. /*
  490.  * Pipe a one line command into a window
  491.  * Bound to ^X @
  492.  */
  493. PASCAL NEAR pipecmd(f, n)
  494.  
  495. int f, n;
  496.  
  497. {
  498.     register WINDOW *wp;    /* pointer to new window */
  499.     register BUFFER *bp;    /* pointer to buffer to zot */
  500.     register char *tmp;    /* ptr to TMP DOS environment variable */
  501.     FILE *fp;
  502.         char line[NLINE];    /* command line send to shell */
  503.     static char bname[] = "command";
  504.     static char filnam[NSTRING] = "command";
  505.     char *getenv();
  506.  
  507.     /* don't allow this command if restricted */
  508.     if (restflag)
  509.         return(resterr());
  510.  
  511.     if ((tmp = getenv("TMP")) == NULL)
  512.         filnam[0] = 0;
  513.     else {
  514.         strcpy(filnam, tmp);
  515.         if (filnam[strlen(filnam) - 1] != '\\')
  516.             strcat(filnam, "\\");
  517.         }
  518.     strcat(filnam,"command");
  519.  
  520.     /* get the command to pipe in */
  521.         if (mlreply("@", line, NLINE) != TRUE)
  522.                 return(FALSE);
  523.  
  524.     /* get rid of the command output buffer if it exists */
  525.         if ((bp=bfind(bname, FALSE, 0)) != FALSE) {
  526.         /* try to make sure we are off screen */
  527.         wp = wheadp;
  528.         while (wp != NULL) {
  529.             if (wp->w_bufp == bp) {
  530.                 onlywind(FALSE, 1);
  531.                 break;
  532.             }
  533.             wp = wp->w_wndp;
  534.         }
  535.         /* get rid of the existing command buffer */
  536.         if (zotbuf(bp) != TRUE)
  537.             return(FALSE);
  538.     }
  539.  
  540.     /* redirect the command output to the output file */
  541.     strcat(line, " >>");
  542.     strcat(line, filnam);
  543.     movecursor(term.t_nrow - 1, 0);
  544.  
  545.     /* execute the command */
  546.     TTkclose();
  547.         shellprog(line);
  548.     TTkopen();
  549.         sgarbf = TRUE;
  550.  
  551.         /* did the output file get generated? */
  552.     if ((fp = fopen(filnam, "r")) == NULL)
  553.         return(FALSE);
  554.     fclose(fp);
  555.  
  556.     /* split the current window to make room for the command output */
  557.     if (splitwind(FALSE, 1) == FALSE)
  558.             return(FALSE);
  559.  
  560.     /* and read the stuff in */
  561.     if (getfile(filnam, FALSE) == FALSE)
  562.         return(FALSE);
  563.  
  564.     /* make this window in VIEW mode, update all mode lines */
  565.     curwp->w_bufp->b_mode |= MDVIEW;
  566.     wp = wheadp;
  567.     while (wp != NULL) {
  568.         wp->w_flag |= WFMODE;
  569.         wp = wp->w_wndp;
  570.     }
  571.  
  572.     /* and get rid of the temporary file */
  573.     unlink(filnam);
  574.     return(TRUE);
  575. }
  576.  
  577. /*
  578.  * filter a buffer through an external DOS program
  579.  * Bound to ^X #
  580.  */
  581. PASCAL NEAR filter(f, n)
  582.  
  583. int f, n;
  584.  
  585. {
  586.         register int    s;    /* return status from CLI */
  587.     register BUFFER *bp;    /* pointer to buffer to zot */
  588.         char line[NLINE];    /* command line send to shell */
  589.     char tmpnam[NFILEN];    /* place to store real file name */
  590.     static char bname1[] = "fltinp";
  591.  
  592.     static char filnam1[] = "fltinp";
  593.     static char filnam2[] = "fltout";
  594.  
  595.     /* don't allow this command if restricted */
  596.     if (restflag)
  597.         return(resterr());
  598.  
  599.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  600.         return(rdonly());    /* we are in read only mode    */
  601.  
  602.     /* get the filter name and its args */
  603.         if ((s=mlreply("#", line, NLINE)) != TRUE)
  604.                 return(s);
  605.  
  606.     /* setup the proper file names */
  607.     bp = curbp;
  608.     strcpy(tmpnam, bp->b_fname);    /* save the original name */
  609.     strcpy(bp->b_fname, bname1);    /* set it to our new one */
  610.  
  611.     /* write it out, checking for errors */
  612.     if (writeout(filnam1, "w") != TRUE) {
  613.         mlwrite(TEXT2);
  614. /*                      "[Cannot write filter file]" */
  615.         strcpy(bp->b_fname, tmpnam);
  616.         return(FALSE);
  617.     }
  618.  
  619.     strcat(line," <fltinp >fltout");
  620.     movecursor(term.t_nrow - 1, 0);
  621.     TTkclose();
  622.         shellprog(line);
  623.     TTkopen();
  624.         sgarbf = TRUE;
  625.     s = TRUE;
  626.  
  627.     /* on failure, escape gracefully */
  628.     if (s != TRUE || (readin(filnam2,FALSE) == FALSE)) {
  629.         mlwrite(TEXT3);
  630. /*                      "[Execution failed]" */
  631.         strcpy(bp->b_fname, tmpnam);
  632.         unlink(filnam1);
  633.         unlink(filnam2);
  634.         return(s);
  635.     }
  636.  
  637.     /* reset file name */
  638.     strcpy(bp->b_fname, tmpnam);    /* restore name */
  639.     bp->b_flag |= BFCHG;        /* flag it as changed */
  640.  
  641.     /* and get rid of the temporary file */
  642.     unlink(filnam1);
  643.     unlink(filnam2);
  644.     return(TRUE);
  645. }
  646.  
  647. #if    LATTICE
  648. extern int _oserr;
  649. #endif
  650.  
  651. #if    AZTEC | MWC
  652. extern int errno;
  653. #endif
  654.  
  655. #if    MSC
  656. extern int _doserrno;
  657. #endif
  658.  
  659. /*    SHELLPROG: Execute a command in a subshell        */
  660.  
  661. PASCAL NEAR shellprog(cmd)
  662.  
  663. char *cmd;    /*  Incoming command line to execute  */
  664.  
  665. {
  666.     char *shell;        /* Name of system command processor */
  667.     char swchar;        /* switch character to use */
  668.     union REGS regs;    /* parameters for dos call */
  669.     char comline[NSTRING];    /* constructed command line */
  670.     char *getenv();
  671.  
  672.     /*  detect current switch character and set us up to use it */
  673.     regs.h.ah = 0x37;    /*  get setting data  */
  674.     regs.h.al = 0x00;    /*  get switch character  */
  675.     intdos(®s, ®s);
  676.     swchar = (char)regs.h.dl;
  677.  
  678.     /*  get name of system shell  */
  679.     if ((shell = getenv("COMSPEC")) == NULL) {
  680.         return(FALSE);        /*  No shell located  */
  681.     }
  682.  
  683.     /* trim leading whitespace off the command */
  684.     while (*cmd == ' ' || *cmd == '\t')    /*  find out if null command */
  685.         cmd++;
  686.  
  687.     /**  If the command line is not empty, bring up the shell  **/
  688.     /**  and execute the command.  Otherwise, bring up the     **/
  689.     /**  shell in interactive mode.   **/
  690.  
  691.     if (*cmd) {
  692.         strcpy(comline, shell);
  693.         strcat(comline, " ");
  694.         comline[strlen(comline) + 1] = 0;
  695.         comline[strlen(comline)] = swchar;
  696.         strcat(comline, "c ");
  697.         strcat(comline, cmd);
  698.         return(execprog(comline));
  699.     } else
  700.         return(execprog(shell));
  701. }
  702.  
  703. /*    EXECPROG:    A function to execute a named program
  704.             with arguments
  705. */
  706.  
  707. #if    LATTICE | AZTEC | MWC
  708. #define    CFLAG    1
  709. #endif
  710.  
  711. PASCAL NEAR execprog(cmd)
  712.  
  713. char *cmd;    /*  Incoming command line to execute  */
  714.  
  715. {
  716.     char *sp;        /* temporary string pointer */
  717.     char f1[38];        /* FCB1 area (not initialized */
  718.     char f2[38];        /* FCB2 area (not initialized */
  719.     char prog[NSTRING];    /* program filespec */
  720.     char tail[NSTRING];    /* command tail with length byte */
  721.     union REGS regs;    /* parameters for dos call  */
  722. #if    MWC == 0
  723.     struct SREGS segreg;    /* segment registers for dis call */
  724. #endif
  725.     struct Pblock {        /* EXEC parameter block */
  726.         short envptr;    /* 2 byte pointer to environment string */
  727.         char *cline;    /* 4 byte pointer to command line */
  728.         char *fcb1;    /* 4 byte pointer to FCB at PSP+5Ch */
  729.         char *fcb2;    /* 4 byte pointer to FCB at PSP+6Ch */
  730.     } pblock;
  731.  
  732.     /* parse the command name from the command line */
  733.     sp = prog;
  734.     while (*cmd && (*cmd != ' ') && (*cmd != '\t'))
  735.         *sp++ = *cmd++;
  736.     *sp = 0;
  737.  
  738.     /* and parse out the command tail */
  739.     while (*cmd && ((*cmd == ' ') || (*cmd == '\t')))
  740.         ++cmd;
  741.     *tail = (char)(strlen(cmd)); /* record the byte length */
  742.     strcpy(&tail[1], cmd);
  743.     strcat(&tail[1], "\r");
  744.  
  745.     /* look up the program on the path trying various extentions */
  746.     if ((sp = flook(prog, TRUE)) == NULL)
  747.         if ((sp = flook(strcat(prog, ".exe"), TRUE)) == NULL) {
  748.             strcpy(&prog[strlen(prog)-4], ".com");
  749.             if ((sp = flook(prog, TRUE)) == NULL)
  750.                 return(FALSE);
  751.         }
  752.     strcpy(prog, sp);
  753.  
  754. #if    MWC == 0
  755.     /* get a pointer to this PSPs environment segment number */
  756.     segread(&segreg);
  757. #endif
  758.  
  759.     /* set up the EXEC parameter block */
  760.     pblock.envptr = 0;    /* make the child inherit the parents env */
  761.     pblock.fcb1 = f1;        /* point to a blank FCB */
  762.     pblock.fcb2 = f2;        /* point to a blank FCB */
  763.         pblock.cline = tail;        /* parameter line pointer */
  764.  
  765.     /* and make the call */
  766.     regs.h.ah = 0x4b;    /* EXEC Load or Execute a Program */
  767.     regs.h.al = 0x00;    /* load end execute function subcode */
  768. #if    AZTEC | MWC
  769.     regs.x.ds = ((unsigned long)(prog) >> 16);    /* program name ptr */
  770.     regs.x.dx = (unsigned int)(prog);
  771.     regs.x.es = regs.x.ds;
  772.     /*regs.x.es = ((unsigned long)(&pblock) >> 16);    * set up param block ptr */
  773.     regs.x.bx = (unsigned int)(&pblock);
  774. #endif
  775. #if    LATTICE | MSC | TURBO | IC | DTL
  776.     segreg.ds = ((unsigned long)(prog) >> 16);    /* program name ptr */
  777.     regs.x.dx = (unsigned int)(prog);
  778.     segreg.es = ((unsigned long)(&pblock) >> 16);    /* set up param block ptr */
  779.     regs.x.bx = (unsigned int)(&pblock);
  780. #endif
  781.  
  782. #if    NOVELL
  783.     rval = execpr(prog, &pblock);
  784. #endif
  785.     
  786. #if    LATTICE && (NOVELL == 0)
  787.     if ((intdosx(®s, ®s, &segreg) & CFLAG) == 0) {
  788.         regs.h.ah = 0x4d;    /* get child process return code */
  789.         intdos(®s, ®s);    /* go do it */
  790.         rval = regs.x.ax;    /* save child's return code */
  791.     } else
  792.         rval = -_oserr;        /* failed child call */
  793. #endif
  794. #if    AZTEC && (NOVELL == 0)
  795.     if ((sysint(0x21, ®s, ®s) & CFLAG) == 0) {
  796.         regs.h.ah = 0x4d;    /* get child process return code */
  797.         sysint(0x21, ®s, ®s);    /* go do it */
  798.         rval = regs.x.ax;    /* save child's return code */
  799.     } else
  800.         rval = -errno;        /* failed child call */
  801. #endif
  802. #if    MWC && (NOVELL == 0)
  803.     intcall(®s, ®s, DOSINT);
  804.     if ((regs.x.flags & CFLAG) == 0) {
  805.         regs.h.ah = 0x4d;    /* get child process return code */
  806.         intcall(®s, ®s, DOSINT);    /* go do it */
  807.         rval = regs.x.ax;    /* save child's return code */
  808.     } else
  809.         rval = -errno;        /* failed child call */
  810. #endif
  811. #if    (TURBO | IC | MSC | DTL) && (NOVELL == 0)
  812.     intdosx(®s, ®s, &segreg);
  813.     if (regs.x.cflag == 0) {
  814.         regs.h.ah = 0x4d;    /* get child process return code */
  815.         intdos(®s, ®s);    /* go do it */
  816.         rval = regs.x.ax;    /* save child's return code */
  817.     } else
  818.         rval = -_doserrno;    /* failed child call */
  819. #endif
  820.     return((rval < 0) ? FALSE : TRUE);
  821. }
  822.  
  823. /* return a system dependant string with the current time */
  824.  
  825. char *PASCAL NEAR timeset()
  826.  
  827. {
  828. #if    MWC | TURBO | IC | MSC
  829.     register char *sp;    /* temp string pointer */
  830.     char buf[16];        /* time data buffer */
  831.     extern char *ctime();
  832.  
  833.     time(buf);
  834.     sp = ctime(buf);
  835.     sp[strlen(sp)-1] = 0;
  836.     return(sp);
  837. #else
  838.     return(errorm);
  839. #endif
  840. }
  841.  
  842. #if    HP150 == 0
  843. /*    extcode:    resolve MSDOS extended character codes
  844.             encoding the proper sequences into emacs
  845.             printable character specifications
  846. */
  847.  
  848. int extcode(c)
  849.  
  850. unsigned c;    /* byte following a zero extended char byte */
  851.  
  852. {
  853.     /* function keys 1 through 9 */
  854.     if (c >= 59 && c < 68)
  855.         return(SPEC | c - 58 + '0');
  856.  
  857.     /* function key 10 */
  858.     if (c == 68)
  859.         return(SPEC | '0');
  860.  
  861.     /* shifted function keys */
  862.     if (c >= 84 && c < 93)
  863.         return(SPEC | SHFT | c - 83 + '0');
  864.     if (c == 93)
  865.         return(SPEC | SHFT | '0');
  866.  
  867.     /* control function keys */
  868.     if (c >= 94 && c < 103)
  869.         return(SPEC | CTRL | c - 93 + '0');
  870.     if (c == 103)
  871.         return(SPEC | CTRL | '0');
  872.  
  873.     /* ALTed function keys */
  874.     if (c >= 104 && c < 113)
  875.         return(SPEC | ALTD | c - 103 + '0');
  876.     if (c == 113)
  877.         return(SPEC | ALTD | '0');
  878.  
  879.     /* ALTed number keys */
  880.     if (c >= 120 && c < 129)
  881.         return(ALTD | c - 119 + '0');
  882.     if (c == 129)
  883.         return(ALTD | '0');
  884.  
  885.     /* some others as well */
  886.     switch (c) {
  887.         case 3:        return(0);        /* null */
  888.         case 15:    return(SHFT | CTRL | 'I');    /* backtab */
  889.  
  890.         case 16:    return(ALTD | 'Q');
  891.         case 17:    return(ALTD | 'W');
  892.         case 18:    return(ALTD | 'E');
  893.         case 19:    return(ALTD | 'R');
  894.         case 20:    return(ALTD | 'T');
  895.         case 21:    return(ALTD | 'Y');
  896.         case 22:    return(ALTD | 'U');
  897.         case 23:    return(ALTD | 'I');
  898.         case 24:    return(ALTD | 'O');
  899.         case 25:    return(ALTD | 'P');
  900.  
  901.         case 30:    return(ALTD | 'A');
  902.         case 31:    return(ALTD | 'S');
  903.         case 32:    return(ALTD | 'D');
  904.         case 33:    return(ALTD | 'F');
  905.         case 34:    return(ALTD | 'G');
  906.         case 35:    return(ALTD | 'H');
  907.         case 36:    return(ALTD | 'J');
  908.         case 37:    return(ALTD | 'K');
  909.         case 38:    return(ALTD | 'L');
  910.  
  911.         case 44:    return(ALTD | 'Z');
  912.         case 45:    return(ALTD | 'X');
  913.         case 46:    return(ALTD | 'C');
  914.         case 47:    return(ALTD | 'V');
  915.         case 48:    return(ALTD | 'B');
  916.         case 49:    return(ALTD | 'N');
  917.         case 50:    return(ALTD | 'M');
  918.  
  919.         case 71:    return(SPEC | '<');    /* HOME */
  920.         case 72:    return(SPEC | 'P');    /* cursor up */
  921.         case 73:    return(SPEC | 'Z');    /* page up */
  922.         case 75:    return(SPEC | 'B');    /* cursor left */
  923.         case 77:    return(SPEC | 'F');    /* cursor right */
  924.         case 79:    return(SPEC | '>');    /* end */
  925.         case 80:    return(SPEC | 'N');    /* cursor down */
  926.         case 81:    return(SPEC | 'V');    /* page down */
  927.         case 82:    return(SPEC | 'C');    /* insert */
  928.         case 83:    return(SPEC | 'D');    /* delete */
  929.         case 115:    return(SPEC | CTRL | 'B');    /* control left */
  930.         case 116:    return(SPEC | CTRL | 'F');    /* control right */
  931.         case 117:    return(SPEC | CTRL | '>');    /* control END */
  932.         case 118:    return(SPEC | CTRL | 'V');    /* control page down */
  933.         case 119:    return(SPEC | CTRL | '<');    /* control HOME */
  934.         case 132:    return(SPEC | CTRL | 'Z');    /* control page up */
  935.     }
  936.  
  937.     return(ALTD | c);
  938. }
  939. #endif
  940.  
  941. #if    TURBO | IC
  942. /*    FILE Directory routines        */
  943.  
  944. char path[NFILEN];    /* path of file to find */
  945. char rbuf[NFILEN];    /* return file buffer */
  946.  
  947. /*    do a wild card directory search (for file name completion) */
  948.  
  949. char *PASCAL NEAR getffile(fspec)
  950.  
  951. char *fspec;    /* pattern to match */
  952.  
  953. {
  954.     register int index;        /* index into various strings */
  955.     register int point;        /* index into other strings */
  956.     register int extflag;        /* does the file have an extention? */
  957.     char fname[NFILEN];        /* file/path for DOS call */
  958.  
  959.     /* first parse the file path off the file spec */
  960.     strcpy(path, fspec);
  961.     index = strlen(path) - 1;
  962.     while (index >= 0 && (path[index] != '/' &&
  963.                 path[index] != '\\' && path[index] != ':'))
  964.         --index;
  965.     path[index+1] = 0;
  966.  
  967.     /* check for an extension */
  968.     point = strlen(fspec) - 1;
  969.     extflag = FALSE;
  970.     while (point > index) {
  971.         if (fspec[point] == '.') {
  972.             extflag = TRUE;
  973.             break;
  974.         }
  975.         point--;
  976.     }
  977.  
  978.     /* construct the composite wild card spec */
  979.     strcpy(fname, path);
  980.     strcat(fname, &fspec[index+1]);
  981.     strcat(fname, "*");
  982.     if (extflag == FALSE)
  983.         strcat(fname, ".*");
  984.  
  985.     /* and call for the first file */
  986.     if (findfirst(fname, &fileblock, FA_DIREC) == -1)
  987.         return(NULL);
  988.  
  989.     /* return the first file name! */
  990.     strcpy(rbuf, path);
  991.     strcat(rbuf, fileblock.ff_name);
  992.     mklower(rbuf);
  993.     if (fileblock.ff_attrib == 16)
  994.         strcat(rbuf, DIRSEPSTR);
  995.     return(rbuf);
  996. }
  997.  
  998. char *PASCAL NEAR getnfile()
  999.  
  1000. {
  1001.     register int index;        /* index into various strings */
  1002.     register int point;        /* index into other strings */
  1003.     register int extflag;        /* does the file have an extention? */
  1004.     char fname[NFILEN];        /* file/path for DOS call */
  1005.  
  1006.     /* and call for the first file */
  1007.     if (findnext(&fileblock) == -1)
  1008.         return(NULL);
  1009.  
  1010.     /* return the first file name! */
  1011.     strcpy(rbuf, path);
  1012.     strcat(rbuf, fileblock.ff_name);
  1013.     mklower(rbuf);
  1014.     if (fileblock.ff_attrib == 16)
  1015.         strcat(rbuf, DIRSEPSTR);
  1016.     return(rbuf);
  1017. }
  1018. #else
  1019. #if    MSC
  1020. /*    FILE Directory routines        */
  1021.  
  1022. char path[NFILEN];    /* path of file to find */
  1023. char rbuf[NFILEN];    /* return file buffer */
  1024.  
  1025. /*    do a wild card directory search (for file name completion) */
  1026.  
  1027. char *PASCAL NEAR getffile(fspec)
  1028.  
  1029. char *fspec;    /* pattern to match */
  1030.  
  1031. {
  1032.     register int index;        /* index into various strings */
  1033.     register int point;        /* index into other strings */
  1034.     register int extflag;        /* does the file have an extention? */
  1035.     char fname[NFILEN];        /* file/path for DOS call */
  1036.  
  1037.     /* first parse the file path off the file spec */
  1038.     strcpy(path, fspec);
  1039.     index = strlen(path) - 1;
  1040.     while (index >= 0 && (path[index] != '/' &&
  1041.                 path[index] != '\\' && path[index] != ':'))
  1042.         --index;
  1043.     path[index+1] = 0;
  1044.  
  1045.     /* check for an extension */
  1046.     point = strlen(fspec) - 1;
  1047.     extflag = FALSE;
  1048.     while (point > index) {
  1049.         if (fspec[point] == '.') {
  1050.             extflag = TRUE;
  1051.             break;
  1052.         }
  1053.         point--;
  1054.     }
  1055.  
  1056.     /* construct the composite wild card spec */
  1057.     strcpy(fname, path);
  1058.     strcat(fname, &fspec[index+1]);
  1059.     strcat(fname, "*");
  1060.     if (extflag == FALSE)
  1061.         strcat(fname, ".*");
  1062.  
  1063.     /* and call for the first file */
  1064.     if (_dos_findfirst(fname, _A_NORMAL|_A_SUBDIR, &fileblock) != 0)
  1065.         return(NULL);
  1066.  
  1067.     /* return the first file name! */
  1068.     strcpy(rbuf, path);
  1069.     strcat(rbuf, fileblock.name);
  1070.     mklower(rbuf);
  1071.     if (fileblock.attrib == 16)
  1072.         strcat(rbuf, DIRSEPSTR);
  1073.     return(rbuf);
  1074. }
  1075.  
  1076. char *PASCAL NEAR getnfile()
  1077.  
  1078. {
  1079.     register int index;        /* index into various strings */
  1080.     register int point;        /* index into other strings */
  1081.     register int extflag;        /* does the file have an extention? */
  1082.     char fname[NFILEN];        /* file/path for DOS call */
  1083.  
  1084.     /* and call for the first file */
  1085.     if (_dos_findnext(&fileblock) != 0)
  1086.         return(NULL);
  1087.  
  1088.     /* return the first file name! */
  1089.     strcpy(rbuf, path);
  1090.     strcat(rbuf, fileblock.name);
  1091.     mklower(rbuf);
  1092.     if (fileblock.attrib == 16)
  1093.         strcat(rbuf, DIRSEPSTR);
  1094.     return(rbuf);
  1095. }
  1096. #else
  1097. char *PASCAL NEAR getffile(fspec)
  1098.  
  1099. char *fspec;    /* file to match */
  1100.  
  1101. {
  1102.     return(NULL);
  1103. }
  1104.  
  1105. char *PASCAL NEAR getnfile()
  1106.  
  1107. {
  1108.     return(NULL);
  1109. }
  1110. #endif
  1111. #endif
  1112. #endif
  1113.